package com.rainbow.gray.plugin.framework.starter.service.aop;

import java.io.IOException;
import java.util.Enumeration;
import java.util.Iterator;
import java.util.List;
import java.util.Map.Entry;

import javax.servlet.http.HttpServletRequest;

import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.http.HttpHeaders;
import org.springframework.http.HttpRequest;
import org.springframework.http.client.ClientHttpRequestExecution;
import org.springframework.http.client.ClientHttpRequestInterceptor;
import org.springframework.http.client.ClientHttpResponse;
import org.springframework.web.context.request.ServletRequestAttributes;

import com.rainbow.gray.framework.constant.GrayConstant;
import com.rainbow.gray.framework.utils.StrategyUtil;
import com.rainbow.gray.plugin.framework.starter.service.constant.ServiceStrategyConstant;
import com.rainbow.gray.plugin.framework.starter.service.context.ServiceStrategyContextHolder;

public class RestTemplateStrategyInterceptor extends AbstractStrategyInterceptor implements ClientHttpRequestInterceptor {
    @Autowired
    protected ServiceStrategyContextHolder serviceStrategyContextHolder;

    // RestTemplate核心策略Header是否传递。当全局订阅启动时，可以关闭核心策略Header传递，这样可以节省传递数据的大小，一定程度上可以提升性能。核心策略Header，包含如下
    // 1. n-d-version
    // 2. n-d-region
    // 3. n-d-address
    // 4. n-d-version-weight
    // 5. n-d-region-weight
    // 6. n-d-id-blacklist
    // 7. n-d-address-blacklist
    // 8. n-d-env (不属于灰度蓝绿范畴的Header，只要外部传入就会全程传递)
    @Value("${" + ServiceStrategyConstant.SPRING_APPLICATION_STRATEGY_REST_TEMPLATE_CORE_HEADER_TRANSMISSION_ENABLED + ":true}")
    protected Boolean restTemplateCoreHeaderTransmissionEnabled;

    public RestTemplateStrategyInterceptor(String contextRequestHeaders, String businessRequestHeaders) {
        super(contextRequestHeaders, businessRequestHeaders);
    }

    @Override
    public ClientHttpResponse intercept(HttpRequest request, byte[] body, ClientHttpRequestExecution execution) throws IOException {
        interceptInputHeader();

        applyInnerHeader(request);
        applyOuterHeader(request);

        interceptOutputHeader(request);

        return execution.execute(request, body);
    }

    private void applyInnerHeader(HttpRequest request) {
        HttpHeaders headers = request.getHeaders();
        headers.add(GrayConstant.N_D_SERVICE_GROUP, pluginAdapter.getGroup());
        headers.add(GrayConstant.N_D_SERVICE_TYPE, pluginAdapter.getServiceType());
        headers.add(GrayConstant.N_D_SERVICE_ID, pluginAdapter.getServiceId());
        headers.add(GrayConstant.N_D_SERVICE_ADDRESS, pluginAdapter.getHost() + ":" + pluginAdapter.getPort());
        headers.add(GrayConstant.N_D_SERVICE_VERSION, pluginAdapter.getVersion());
        headers.add(GrayConstant.N_D_SERVICE_REGION, pluginAdapter.getRegion());
        headers.add(GrayConstant.N_D_SERVICE_ENVIRONMENT, pluginAdapter.getEnvironment());
        headers.add(GrayConstant.N_D_SERVICE_ZONE, pluginAdapter.getZone());
    }

    private void applyOuterHeader(HttpRequest request) {
        ServletRequestAttributes attributes = serviceStrategyContextHolder.getRestAttributes();
        if (attributes == null) {
            return;
        }

        HttpServletRequest previousRequest = attributes.getRequest();
        Enumeration<String> headerNames = previousRequest.getHeaderNames();
        if (headerNames == null) {
            return;
        }

        HttpHeaders headers = request.getHeaders();
        while (headerNames.hasMoreElements()) {
            String headerName = headerNames.nextElement();
            String headerValue = previousRequest.getHeader(headerName);
            boolean isHeaderContains = isHeaderContainsExcludeInner(headerName.toLowerCase());
            if (isHeaderContains) {
                if (restTemplateCoreHeaderTransmissionEnabled) {
                    headers.add(headerName, headerValue);
                } else {
                    boolean isCoreHeaderContains = StrategyUtil.isCoreHeaderContains(headerName);
                    if (!isCoreHeaderContains) {
                        headers.add(headerName, headerValue);
                    }
                }
            }
        }
    }

    private void interceptOutputHeader(HttpRequest request) {
        if (!interceptDebugEnabled) {
            return;
        }

        System.out.println("------- " + getInterceptorName() + " Intercept Output Header Information ------");
        HttpHeaders headers = request.getHeaders();
        for (Iterator<Entry<String, List<String>>> iterator = headers.entrySet().iterator(); iterator.hasNext();) {
            Entry<String, List<String>> header = iterator.next();
            String headerName = header.getKey();
            boolean isHeaderContains = isHeaderContains(headerName.toLowerCase());
            if (isHeaderContains) {
                List<String> headerValue = header.getValue();

                System.out.println(headerName + "=" + headerValue);
            }
        }
        System.out.println("--------------------------------------------------");
    }

    @Override
    protected String getInterceptorName() {
        return "RestTemplate";
    }
}